﻿using SmartDevice.Library.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using XY.Communication;

namespace SmartDevice.Library.Device.Power
{
    public class DCPowerMaster : IPowerMaster
    {
        private UDPClient MyUDPClient = null;
        private IPEndPoint deviceIPEndPoint = null;

        private readonly ManualResetEvent DisConnectResetEvent = new ManualResetEvent(false);
        private readonly ManualResetEvent ReceivedDataResetEvent = new ManualResetEvent(false);

        public event DeviceFaultEventHandler DeviceFault;
        public event StatusReportEventHandler StatusReport;

        public bool Connect(NetworkConfig networkConfig)
        {
            try
            {
                deviceIPEndPoint = new IPEndPoint(IPAddress.Parse(networkConfig.DeviceIP), networkConfig.DevicePort);
                MyUDPClient = new UDPClient(networkConfig.LocalIP, networkConfig.LocalPort);
                MyUDPClient.UDPMessageReceived += MyUDPClient_UDPMessageReceived;

                CheckDeviceOnline();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public void DisConnect()
        {
            Debug.WriteLine("DisConnect...");
            DisConnectResetEvent.Set();
            MyUDPClient?.CloseUDP();
            MyUDPClient = null;
        }

        //检查设备离线
        private void CheckDeviceOnline()
        {
            Task.Run(() =>
            {
                int WaitTime = 0;
                while (true)
                {
                    SendNeedReport();

                    if (DisConnectResetEvent.WaitOne(1000))
                    {
                        break;
                    }

                    WaitTime++;

                    if (ReceivedDataResetEvent.WaitOne(1))
                    {
                        ReceivedDataResetEvent.Reset();
                        WaitTime = 0;
                    }

                    if (WaitTime > 3)
                    {
                        DeviceFaultEventArgs args = new DeviceFaultEventArgs()
                        {
                            FaultCode = "F01",
                            FaultInfo = "设备离线"
                        };
                        DeviceFault?.Invoke(args);
                        WaitTime = 0;
                    }
                }

                Debug.WriteLine("检查设备离线线程结束");
            });
        }

        //下发询问状态的参数
        private void SendNeedReport()
        {
            //01 03 03 00 F1 28 
            byte[] cmd = new byte[] { 0x01, 0x03, 0x03, 0x00, 0xF1, 0x28 };
            MyUDPClient?.SendData(deviceIPEndPoint, cmd);
        }

        private void MyUDPClient_UDPMessageReceived(UdpStateEventArgs args)
        {
            ReceivedDataResetEvent.Set();

            //Debug.WriteLine($"Received data length={args.buffer.Length}");

            // 01 03 03 06 S1 S2 V_Hi V_Low Cur_Hi Cur_Low CRC_Hi CRC_Low
            if (args.buffer.Length == 12)
            {
                if (args.buffer[4] == 0x00 && args.buffer[5] == 0x00)
                {
                    StatusReport?.Invoke(new PowerReportEventArgs { PowerStatus = PowerStatus.OFF });
                }

                if (args.buffer[4] == 0xFF && args.buffer[5] == 0xFF)
                {
                    ushort voltage = BitConverter.ToUInt16(new byte[] { args.buffer[7], args.buffer[6] }, 0);
                    ushort current = BitConverter.ToUInt16(new byte[] { args.buffer[9], args.buffer[8] }, 0);
                    StatusReport?.Invoke(new PowerReportEventArgs
                    {
                        PowerStatus = PowerStatus.ON,
                        Voltage = (float)voltage / 10,
                        Current = (float)current / 10,
                    });
                }
            }
        }

        public void SetPowerON(double voltage, double current = 10)
        {
            //01 01 03 FF FF V_Hi V_Low Cur_Hi Cur_Low CRC_Hi CRC_Low
            byte[] data = new byte[] { 0x01, 0x01, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

            byte[] v = BitConverter.GetBytes((ushort)(voltage * 10));
            data[5] = v[1];
            data[6] = v[0];

            byte[] C = BitConverter.GetBytes((ushort)(current * 10));
            data[7] = C[1];
            data[8] = C[0];

            data = CRC.CalCRC16a(data);
            MyUDPClient?.SendData(deviceIPEndPoint, data);
        }

        public void SetPowerOFF()
        {
            //01 01 03 00 00 E8 3C
            byte[] data = new byte[] { 0x01, 0x01, 0x03, 0x00, 0x00, 0xE8, 0x3C };
            MyUDPClient?.SendData(deviceIPEndPoint, data);
        }
    }
}

/*
 * 通信协议 * 
 
    1、下发询问状态
    01 03 03 00 F1 28 
    固定内容

    答复：
    01 03 03 06 S1 S2 V_Hi V_Low Cur_Hi Cur_Low CRC_Hi CRC_Low
    S1 S2:设备状态 00 00 表示PowerOFF。 FF FF表示设备PowerON
    V_Hi V_Low：电压值，高位在前、低位在后,单位是0.1V
    Cur_Hi Cur_Low：电流值，高位在前、低位在后,单位是0.1A

    2、PowerOFF命令
    01 01 03 00 00 E8 3C

    3、PowerON并设置电压、电流
    01 01 03 FF FF V_Hi V_Low Cur_Hi Cur_Low CRC_Hi CRC_Low

 */